﻿using System;
using System.Diagnostics;

namespace Codeplex.InertialScroll
{
    public static class AccCalc
    {
        /// 
        /// <summary>
        /// Calculate speed for passed acceleration, time and initial speed</summary>
        /// 
        public static double CalculateSpeed(
            double                                       acceleration,
            double                                       time,
            double                                       speed0
        )
        {
            return acceleration * time + speed0;
        }

        /// 
        /// <summary>
        /// Calculate acceleration to fully stop for passed initial speed and time</summary>
        /// 
        public static double CalculateAcceleration(
            double                                       speed0,
            double                                       time
        )
        {
            Debug.Assert(speed0 == 0 || time > 0);

            return (0 - speed0) / time;
        }

        /// 
        /// <summary>
        /// Calculate acceleration necessary to stop at passed distance by passed time with passed 
        /// initial speed.</summary>
        /// 
        public static double GetStopAcceleration(
            double                                       distance,
            double                                       speed0,
            double                                       time
        )
        {
            Debug.Assert(distance == 0 || time > 0);

            return ((distance - speed0 * time) * 2) / Math.Pow(time, 2);
        }

        /// 
        /// <summary>
        /// Calculate new position for passed initial position acceleration, speed and time</summary>
        /// 
        public static double CalculatePosition(
            double                                       position0,
            double                                       acceleration,
            double                                       speed0,
            double                                       time
        )
        {
            Debug.Assert(time >= 0);

            return position0 + ((acceleration * (double) Math.Pow(time, 2)) / 2) + speed0 * time;
        }

        /// 
        /// <summary>
        /// Calculate time necessary to get to distance for passed initial speed and acceleration</summary>
        /// 
        public static double CalculateTime(
            double                                       speed0, 
            double                                       acceleration, 
            double                                       distance
        )
        {
            double                                       time1;
            double                                       time2;

            time1 = (-speed0 + (double) Math.Sqrt(Math.Pow(speed0, 2) - 2 * acceleration * distance)) / acceleration;
            time2 = (-speed0 - (double) Math.Sqrt(Math.Pow(speed0, 2) - 2 * acceleration * distance)) / acceleration;

            return (time1 > 0 && time2 > 0 ? Math.Min(time1, time2) : time1 < 0 ? time2 : time1);
        }
    }
}
